﻿// <copyright file="NodePropertyEditor.cs" company="City of Portland, BES-ASM">
// </copyright>
// <summary>NodePropertyEditor Form</summary>

namespace BESASM.EMGAATS.UI
{
  using System;
  using System.Collections.Generic;
  using System.ComponentModel;
  using System.Data;
  using System.Drawing;
  using System.Linq;
  using System.Text;
  using System.Threading.Tasks;
  using System.Windows.Forms;
  using BESASM.EMGAATS.BusinessClasses;

  /// <summary>
  /// A form for editing node properties.
  /// </summary>
  public partial class NodePropertyEditor : Form
  {
    private INode original = null;
    private INode clone = null;
    private bool validating = false;

    /// <summary>
    /// Initializes a new instance of the <see cref="NodePropertyEditor"/> class.
    /// </summary>
    public NodePropertyEditor()
    {
      this.InitializeComponent();

      foreach (var nodeType in Enum.GetValues(typeof(NodeType)))
      {
        this.nodeTypeComboBox.Items.Add(nodeType);
      }

      foreach (var topType in Enum.GetValues(typeof(NodeTopType)))
      {
        this.topTypeComboBox.Items.Add(topType);
      }
    }

    /// <summary>
    /// Fired when the Node has been edited
    /// </summary>
    public event EventHandler<CancelEventArgs> NodeChanged;

    /// <summary>
    /// Gets or sets the node to be edited.
    /// </summary>
    public INode Node
    {
      get
      {
        return this.original;
      }

      set
      {
        this.original = value;
        this.nodeBindingSource.DataSource = this.original.Clone();
      }
    }

    /// <summary>
    /// Gets the candidate node with values modified by the user. These values will be transferred to the original entity when the changes are committed.
    /// </summary>
    public INode Candidate
    {
      get
      {
        return this.nodeBindingSource.DataSource as INode;
      }
    }

    /// <summary>
    /// Raises NodeChanged event.
    /// </summary>
    /// <returns>True if the event handlers determine the node changes should be cancelled.</returns>
    protected bool OnNodeChanged()
    {
      if (this.NodeChanged != null)
      {
        CancelEventArgs cancelArgs = new CancelEventArgs();
        this.NodeChanged(this, cancelArgs);
        return cancelArgs.Cancel;
      }

      return false;
    }

    private void CancelButton_Click(object sender, EventArgs e)
    {
      this.Close();
    }

    private void OkButton_Click(object sender, EventArgs e)
    {
      this.validating = true;
      try
      {
        if (this.Candidate != null)
        {
          bool cancel = false;

          this.nameTextBox.DataBindings["Text"].WriteValue();
          this.nodeTypeComboBox.DataBindings["SelectedItem"].WriteValue();
          this.groundTextBox.DataBindings["Text"].WriteValue();
          this.diameterTextBox.DataBindings["Text"].WriteValue();
          this.topTypeComboBox.DataBindings["SelectedItem"].WriteValue();

          NodeValidator validator = new NodeValidator(RuleSet.PropertyDialog);
          var results = validator.Validate(this.Candidate);

          if (results.HasErrors())
          {
            string message = string.Empty;
            foreach (var error in results.GetErrors())
            {
              message += error.ErrorMessage + Environment.NewLine;
            }

            MessageBox.Show(this, message, "Error", MessageBoxButtons.OK, MessageBoxIcon.Error);
            cancel = true;
          }
          else if (results.HasWarnings())
          {
            string message = string.Empty;
            foreach (var warning in results.GetWarnings())
            {
              message += warning.ErrorMessage + Environment.NewLine;
            }

            if (results.HasInfo())
            {
              message += Environment.NewLine;
            }

            foreach (var info in results.GetInfo())
            {
              message += info.ErrorMessage + Environment.NewLine;
            }

            DialogResult response = MessageBox.Show(this, message, "Warning", MessageBoxButtons.OKCancel, MessageBoxIcon.Warning, MessageBoxDefaultButton.Button1);
            cancel = response == System.Windows.Forms.DialogResult.Cancel;
          }
          else if (results.HasInfo())
          {
            string message = string.Empty;
            foreach (var info in results.GetInfo())
            {
              message += info.ErrorMessage + Environment.NewLine;
            }

            MessageBox.Show(this, message, "Information", MessageBoxButtons.OK, MessageBoxIcon.Information);
          }

          cancel = cancel || this.OnNodeChanged();

          if (!cancel)
          {
            this.CommitChanges();
            this.validating = false;
            this.DialogResult = DialogResult.OK;
            this.Close();
          }
        }
      }
      finally
      {
        this.validating = false;
      }
    }

    private void CommitChanges()
    {
      this.Node.NodeName = this.Candidate.NodeName;
      this.Node.NodeType = this.Candidate.NodeType;
      this.Node.GroundElevFt = this.Candidate.GroundElevFt;
      this.Node.DiameterFt = this.Candidate.DiameterFt;
      this.Node.TopType = this.Candidate.TopType;
    }
  }
}
